﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SLogo.Helper;

namespace SLogo.Compile
{
    /// <summary>
    /// 词法分析
    /// </summary>
    class LexicalAnalysis
    {
        /// <summary>
        /// logo语言源代码
        /// </summary>
        public static Stack<String> SourceCode { get; set; }
        /// <summary>
        /// 当前识别到的单词
        /// </summary>
        public static String Token { get; set; }
        /// <summary>
        /// 当前读入的字符
        /// </summary>
        public static char CurrentChar { get; set; }
        /// <summary>
        /// 当前识别到的单词的种别编码
        /// </summary>
        public static int Syn { get; set; }
        /// <summary>
        /// 扫描源程序时的游标
        /// </summary>
        public static int Pointer { get; set; }
        /// <summary>
        /// 识别到的数字的数值
        /// </summary>
        public static double Sum { get; set; }
        /// <summary>
        /// 源程序行号
        /// </summary>
        public static int Line { get; set; }
        /// <summary>
        /// 用来存放引用文件的栈
        /// </summary>
        public static Stack<String> FilenameStack { get; set; }
        /// <summary>
        /// 用来存放'['的栈
        /// </summary>
        public static Stack<String> SignStack { get; set; }
        /// <summary>
        /// 词法分析是否成功
        /// </summary>
        public static bool Success { get; private set; }
        /// <summary>
        /// 不同文件中的种别编码信息
        /// </summary>
        public static List<Int32> ListSyn { get; set; }

        /// <summary>
        /// 静态初始化
        /// </summary>
        static LexicalAnalysis()
        {
            Line = 1;
            SourceCode=new Stack<string>();
            FilenameStack = new Stack<string>();
            SignStack = new Stack<string>();
            Success = true;
            ListSyn=new List<int>();
            Token = "";
            CurrentChar = (char)0;
            Syn = -1;
            Pointer = 0;
            Sum = 0;
        }
        /// <summary>
        /// 读取下一个字符
        /// </summary>
        public static void Scanner()
        {
            Syn = 0;
            Token = ""; //当前单词为空
            if (Pointer >= SourceCode.Peek().Length) //若浮标超过了长度，返回
            {
                return;
            }
            CurrentChar = SourceCode.Peek()[Pointer++]; //当前读入的字符
            while (CurrentChar == ' ') //去掉对于的空格
            {
                if (Pointer < SourceCode.Peek().Length)
                    CurrentChar = SourceCode.Peek()[Pointer++]; //得到当前字符
                else
                {
                    return;
                }
            }
            if (CurrentChar == '"') //字符串开始标志
            {
                Token += CurrentChar;
                if (Pointer < SourceCode.Peek().Length)
                {
                    CurrentChar = SourceCode.Peek()[Pointer++];
                }
                else
                {
                    ConsoleHelper.StdErr(String.Format("词法错误：字符串没有结束标志\n\t错误位置：{1} line {0}\n", Line,
                                                       FilenameStack.Peek()));
                    Success = false;
                    Syn = -1; //出错了
                    Scanner();
                    return;
                }
                while (CurrentChar != '"' && CurrentChar != '\n') //不是换行或字符串结束标志不跳出
                {
                    if (CurrentChar == 92) //转义
                    {
                        //while (CurrentChar == 92) //多个反斜杠转义为一个
                        //{
                        //    CurrentChar = SourceCode.Peek()[Pointer++];
                        //}
                        //if (CurrentChar != '\n' && CurrentChar != '"')
                        //{
                        //    Token += '\\'.ToString(); //非转义，单词加上字符
                        //}
                        if (CurrentChar == '\n')
                        {
                            if (Pointer < SourceCode.Peek().Length)
                                CurrentChar = SourceCode.Peek()[Pointer++];
                            Line++; //遇到回车行数加一
                            ConsoleHelper.StdErr(String.Format("词法错误：字符串没有结束标志\n\t错误位置：{1} line {0}\n", Line,
                                                       FilenameStack.Peek()));
                            Success = false;
                            Syn = -1; //出错了
                            Scanner();
                            return;
                        }
                    }
                    Token += CurrentChar;
                    if (Pointer < SourceCode.Peek().Length)
                    {
                        CurrentChar = SourceCode.Peek()[Pointer++];
                    }
                    else
                    {
                        ConsoleHelper.StdErr(String.Format("词法错误：字符串没有结束标志\n\t错误位置：{1} line {0}\n", Line,
                                                       FilenameStack.Peek()));
                        Success = false;
                        Syn = -1; //出错了
                        Scanner();
                        return;
                    }
                }
                if (CurrentChar == '"') //字符串结束
                {
                    Token += CurrentChar;
                    Syn = 131;
                    ListSyn.Add(Syn);
                    return;
                }
                Line++;
                ConsoleHelper.StdErr(String.Format("词法错误：字符串没有结束标志\n\t错误位置：{1} line {0}\n", Line,
                                                       FilenameStack.Peek()));
                Success = false;
                Syn = -1; //出错了
                Scanner();
            }
            else if (CurrentChar >= 97 && CurrentChar <= 122 || CurrentChar == '_') //标识符或关键字
            {
                Token += CurrentChar;
                if (Pointer < SourceCode.Peek().Length)
                {
                    CurrentChar = SourceCode.Peek()[Pointer++]; //读取下个单词
                }
                else
                {
                    Syn = 132;
                    ListSyn.Add(Syn);
                    return;
                }
                while (CurrentChar >= 97 && CurrentChar <= 122 || CurrentChar == '_' ||
                       CurrentChar >= 48 && CurrentChar <= 57) //若为标识符的成员，继续读
                {
                    Token += CurrentChar;
                    if (Pointer < SourceCode.Peek().Length)
                    {
                        CurrentChar = SourceCode.Peek()[Pointer++]; //读取下个单词
                    }
                    else
                    {
                        break;
                    }
                }
                if (CurrentChar == ' ' || CurrentChar == '\n' ||ListSyn.Count!=0&& ListSyn.ElementAt(ListSyn.Count - 1) == 139 || Pointer >= SourceCode.Peek().Length||CurrentChar==']')
                {
                    if (
                        !(CurrentChar >= 97 && CurrentChar <= 122 || CurrentChar == '_' ||
                          CurrentChar >= 48 && CurrentChar <= 57))
                    {
                        Pointer--;
                    }
                    if (Token.Equals("to")) //关键字to
                    {
                        Syn = 1;
                        ListSyn.Add(Syn);
                        return;
                    }
                    if (Token.Equals("end")) //关键字end
                    {
                        Syn = 2;
                        ListSyn.Add(Syn);
                        return;
                    }
                    if (Token.Equals("include")) //关键字include
                    {
                        Syn = 3;
                        ListSyn.Add(Syn);
                        return;
                    }
                    Syn = 132;
                    ListSyn.Add(Syn);
                }
                else
                {
                    //一些错误处理
                    ConsoleHelper.StdErr(String.Format("词法错误：命令和参数之间没有空格\n\t错误位置：{1} line {0}\n", Line,
                                                       FilenameStack.Peek()));
                    Success = false;
                    Syn = -1;
                    Scanner();
                }
            }
            else if (CurrentChar == '.') //数字
            {
                Token += CurrentChar;
                if (Pointer < SourceCode.Peek().Length)
                {
                    CurrentChar = SourceCode.Peek()[Pointer++]; //读取下个单词
                }
                if (CurrentChar < 48 || CurrentChar > 57)
                {
                    ConsoleHelper.StdErr(String.Format("词法错误：应为数字字符\n\t错误位置：{1} line {0}\n", Line,
                                                       FilenameStack.Peek()));
                    Success = false;
                    Syn = -1;
                    Scanner();
                    return;
                }
                while (CurrentChar >= 48 && CurrentChar <= 57) //字符为数字
                {
                    Token += CurrentChar;
                    if (Pointer < SourceCode.Peek().Length)
                    {
                        CurrentChar = SourceCode.Peek()[Pointer++]; //读取下个单词
                    }
                    else
                    {
                        break;
                    }
                }
                if (CurrentChar < 48 || CurrentChar > 57)
                {
                    Pointer--;
                    if (CurrentChar != '|' && CurrentChar != '&' && CurrentChar != '[' && CurrentChar != '>' && CurrentChar != '<' && CurrentChar != '=' && CurrentChar != '!' && CurrentChar != ')' && CurrentChar != ']' && CurrentChar != ' ' && CurrentChar != '+' && CurrentChar != '-' && CurrentChar != '*' && CurrentChar != '/' && CurrentChar != '+' && CurrentChar != '\n' && Pointer < SourceCode.Peek().Length)
                    {
                        //一些错误处理
                        ConsoleHelper.StdErr(String.Format("词法错误：\":\"数值常量错误!：{1} line {0}\n", Line,
                                                           FilenameStack.Peek()));
                        Success = false;
                        Syn = -1;
                        Scanner();
                        return;
                    }
                }
                Syn = 130;
                ListSyn.Add(Syn);
                Sum = Double.Parse(Token);
            }
            else if (CurrentChar >= 48 && CurrentChar <= 57) //字符为数字
            {
                Syn = 130;
                Token += CurrentChar;
                if (Pointer < SourceCode.Peek().Length)
                {
                    CurrentChar = SourceCode.Peek()[Pointer++]; //读取下个单词
                }
                else
                {
                    Sum = Double.Parse(Token);
                    ListSyn.Add(Syn);
                    return;
                }
                while (CurrentChar >= 48 && CurrentChar <= 57)
                {
                    Token += CurrentChar;
                    if (Pointer < SourceCode.Peek().Length)
                        CurrentChar = SourceCode.Peek()[Pointer++]; //读取下个单词
                    else
                    {
                        Pointer++;
                        break;
                    }
                }
                if (CurrentChar == '.')
                {
                    Token += CurrentChar;
                    if (Pointer < SourceCode.Peek().Length)
                    {
                        CurrentChar = SourceCode.Peek()[Pointer++]; //读取下个单词
                    }
                    else
                    {
                        Sum = Double.Parse(Token);
                        ListSyn.Add(Syn);
                        return;
                    }
                    while (CurrentChar >= 48 && CurrentChar <= 57) //字符为数字
                    {
                        Token += CurrentChar;
                        if (Pointer < SourceCode.Peek().Length)
                        {
                            CurrentChar = SourceCode.Peek()[Pointer++]; //读取下个单词
                        }
                        else
                        {
                            break;
                        }
                    }
                    if (CurrentChar < 48 || CurrentChar > 57)
                    {
                        Pointer--;
                        if (CurrentChar != '|' && CurrentChar != '&' && CurrentChar != '[' && CurrentChar != '>' && CurrentChar != '<' && CurrentChar != '=' && CurrentChar != '!' && CurrentChar != ')' && CurrentChar != ']' && CurrentChar != ' ' && CurrentChar != '+' && CurrentChar != '-' && CurrentChar != '*' && CurrentChar != '/' && CurrentChar != '+' && CurrentChar != '\n' && Pointer < SourceCode.Peek().Length)
                        {
                            //一些错误处理
                            ConsoleHelper.StdErr(String.Format("词法错误：\":\"数值常量错误!：{1} line {0}\n", Line,
                                                               FilenameStack.Peek()));
                            Success = false;
                            Syn = -1;
                            Scanner();
                            return;
                        }
                       
                    }
                    Sum = Double.Parse(Token);
                    ListSyn.Add(Syn);
                }
                else
                {
                    Pointer--;
                    if (CurrentChar != '|' && CurrentChar != '&' && CurrentChar != '[' && CurrentChar != '>' && CurrentChar != '<' && CurrentChar != '=' && CurrentChar != '!' && CurrentChar != ')' && CurrentChar != ']' && CurrentChar != '.' && CurrentChar != ' ' && CurrentChar != '+' && CurrentChar != '-' && CurrentChar != '*' && CurrentChar != '/' && CurrentChar != '+' && CurrentChar != '\n' && Pointer < SourceCode.Peek().Length)
                    {
                        //一些错误处理
                        ConsoleHelper.StdErr(String.Format("词法错误：\":\"数值常量错误!：{1} line {0}\n", Line,
                                                           FilenameStack.Peek()));
                        Success = false;
                        Syn = -1;
                        Scanner();
                        return;
                    }
                    Sum = Double.Parse(Token);
                    ListSyn.Add(Syn);
                    return;
                }
            }
            else switch (CurrentChar)
            {
                case ':':
                    Token += CurrentChar;
                    Syn = 139;
                    if (SourceCode.Peek()[Pointer]==' ')
                    {
                        //一些错误处理
                        ConsoleHelper.StdErr(String.Format("词法错误：\":\"和引用变量之间不能有空格\n\t错误位置：{1} line {0}\n", Line,
                                                           FilenameStack.Peek()));
                        Success = false;
                        Syn = -1;
                        Scanner();
                        return;
                    }
                    ListSyn.Add(Syn);
                    return;
                case '-':
                case '+':
                    {
                        Token += CurrentChar;
                        Syn = CurrentChar == '+' ? 43 : 45;
                        int addsign = Pointer;
                        if (Pointer == 1||ListSyn.Count<2) //当+或-在开头
                        {
                            //将+/-a变为(0+/-a)
                            SourceCode.Push(SourceCode.Pop().Insert(Pointer - 1, "(0"));
                            Pointer += 2;
                            Scanner(); //读入下个字符
                            if(CurrentChar==':')
                            {
                                Scanner();
                            }
                            SourceCode.Push(SourceCode.Pop().Insert(Pointer, ")"));  //在下个字符后添加')'
                            Syn = 40;
                            ListSyn.Add(Syn);
                            Token = "("; //第一个读出的是'('
                            Pointer = addsign;
                            return;
                        }
                        if (ListSyn.ElementAt(ListSyn.Count - 1) == 42 || ListSyn.ElementAt(ListSyn.Count - 1) == 47 || ListSyn.ElementAt(ListSyn.Count - 1) == 40 || ListSyn.ElementAt(ListSyn.Count - 1) == 132 && ListSyn.ElementAt(ListSyn.Count - 2) != 139 || ListSyn.ElementAt(ListSyn.Count - 1) == 131 || ListSyn.ElementAt(ListSyn.Count - 1) >= 133 && ListSyn.ElementAt(ListSyn.Count - 1) <= 138 || ListSyn.ElementAt(ListSyn.Count - 1) >= 140 && ListSyn.ElementAt(ListSyn.Count - 1) <= 142)
                            //+或-需要当作正负符号
                        {
                            //将+/-a变为(0+/-a)
                            SourceCode.Push(SourceCode.Pop().Insert(Pointer - 1, "(0"));
                            Pointer += 2;
                            Scanner(); //读入下个字符
                            if (CurrentChar == ':')
                            {
                                Scanner();
                            }
                            SourceCode.Push(SourceCode.Pop().Insert(Pointer, ")"));  //在下个字符后添加')'
                            Syn = 40;
                            ListSyn.Add(Syn);
                            Token = "("; //第一个读出的是'('
                            Pointer = addsign;
                            return;
                        }
                    }
                    break;
                case '*':
                    Syn = 42;
                    Token += CurrentChar;
                    ListSyn.Add(Syn);
                    return;
                case '/':
                    Syn = 47;
                    ListSyn.Add(Syn);
                    Token += CurrentChar;
                    return;
                case '(':
                    Syn = 40;
                    ListSyn.Add(Syn);
                    Token += CurrentChar;
                    return;
                case ')':
                    Syn = 41;
                    ListSyn.Add(Syn);
                    Token += CurrentChar;
                    return;
                case '{':
                    Syn = 124;
                    ListSyn.Add(Syn);
                    Token += CurrentChar;
                    return;
                case '}':
                    Syn = 125;
                    ListSyn.Add(Syn);
                    Token += CurrentChar;
                    return;
                case '[':
                    Syn = 91;
                    ListSyn.Add(Syn);
                    Token += CurrentChar;
                    SignStack.Push("[");
                    return;
                case ']':
                    Syn = 93;
                    ListSyn.Add(Syn);
                    Token += CurrentChar;
                    if (SignStack.Count > 0)
                    {
                        SignStack.Pop();
                    }
                    return;
                case '\n':
                    if (SignStack.Count == 0)
                    {
                        Syn = 10;
                        ListSyn.Add(Syn);
                        Line++;
                        Token += CurrentChar;
                        return;
                    }
                    Line++;
                    Scanner();
                    break;
                case '!':
                    Syn = 140;
                    Token += CurrentChar;
                    if (Pointer < SourceCode.Peek().Length)
                    {
                        CurrentChar = SourceCode.Peek()[Pointer++]; //读取下个单词
                    }
                    else
                    {
                        ListSyn.Add(Syn);
                        return;
                    }
                    if (CurrentChar == '=') //字符为!=
                    {
                        Syn = 138;
                        Token += CurrentChar;
                        ListSyn.Add(Syn);
                        return;
                    }
                    Pointer--;
                    ListSyn.Add(Syn);
                    break;
                case '|':
                    Syn = 141;
                    ListSyn.Add(Syn);
                    Token += CurrentChar;
                    return;
                case '&':
                    Syn = 142;
                    ListSyn.Add(Syn);
                    Token += CurrentChar;
                    return;
                case '>':
                    Syn = 133;
                    Token += CurrentChar;
                    if (Pointer < SourceCode.Peek().Length)
                    {
                        CurrentChar = SourceCode.Peek()[Pointer++]; //读取下个单词
                    }
                    else
                    {
                        ListSyn.Add(Syn);
                        return;
                    }
                    if (CurrentChar == '=') //字符为>=
                    {
                        Syn = 134;
                        Token += CurrentChar;
                        ListSyn.Add(Syn);
                        return;
                    }
                    ListSyn.Add(Syn);
                    Pointer--;
                    break;
                case '<':
                    Syn = 135;
                    Token += CurrentChar;
                    if (Pointer < SourceCode.Peek().Length)
                    {
                        CurrentChar = SourceCode.Peek()[Pointer++]; //读取下个单词
                    }
                    else
                    {
                        ListSyn.Add(Syn);
                        return;
                    }
                    if (CurrentChar == '=') //字符为<=
                    {
                        Syn = 136;
                        Token += CurrentChar;
                        ListSyn.Add(Syn);
                        return;
                    }
                    ListSyn.Add(Syn);
                    Pointer--;
                    break;
                case '=':
                    Syn = 137;
                    Token += CurrentChar;
                    ListSyn.Add(Syn);
                    return;
            }
        }
    }
}
